#include "config.h"

static uint8_t calc_chk( const uint8_t *buf );
static Bool validate( const uint8_t *buf );
static void process( uint8_t rp, uint8_t wp );
static const uint8_t HEAD = 0XAA;
static const uint8_t FILL = 0X55;
static uint8_t self_addr = 'B';
static struct dc_msg msg_buf;
static pMsgBox tbox = NULL;
static SysMsg recvmsg = {
		.data = &msg_buf,
};
inline void dc_set_addr( uint8_t addr )
{
	self_addr = addr;
}
inline void dc_set_mid( uint8_t mid )
{
	recvmsg.id = mid;
}
inline void dc_set_wait( pMsgBox mb )
{
	tbox = mb;
}
static inline void notice_wait( void )
{
	if( tbox != NULL ){
		sendSysMsg( tbox, &recvmsg );
	}
}
DEF_TASK( daisy_10, 128, 1 )
{
	while( True ){
		process( 1, 0 );
	}
}
DEF_TASK( daisy_01, 128, 1 )
{
	while( True ){
		process( 0, 1 );
	}
}

void load_dc_msg( struct dc_msg *m, uint8_t *buf )
{
	m->addr = buf[2];
	m->id = buf[3];
	memcpy( m->data, &buf[4], 4 );
}

void dc_send( const struct dc_msg *m )
{
	uint8_t sb[9];
	sb[0] = HEAD;
	sb[1] = m->addr;
	sb[2] = self_addr;
	sb[3] = m->id;
	memcpy( &sb[4], m->data, 4 );
	sb[8] = calc_chk( sb );
	usartWrite( (m->addr < self_addr) ? 0 : 1, sb, 9 );
}

static uint8_t calc_chk( const uint8_t *buf )
{
	uint8_t i;
	uint8_t ret = 0;
	for( i = 1; i < 8; ++i ){
		ret += buf[i];
	}
	return 0 - ret;
}

static Bool validate( const uint8_t *buf )
{
	register uint8_t i;
	register uint8_t sum;
	for( i = 1; i < 9; ++i )
		sum += buf[i];
	return PARSE_BOOL( sum == 0 );
}

static void process( uint8_t rp, uint8_t wp )
{
	uint8_t buf[9];
	if( usartRead( rp, buf, 1 ) != 1)
		return;
	if( buf[0] == HEAD ){
		if( usartRead( rp, &buf[1], 8 ) != 8 )
			return;
		if( validate( buf ) ){
			if( buf[1] == self_addr ){
				load_dc_msg( &msg_buf, buf );
				notice_wait();
			} else {
				usartWrite( wp, buf, 9 );
			}
		}
	}
}

void dc_msg_print( struct dc_msg *m )
{
	char info[16] = "F";
	itoa( m->addr, &info[1], 16 );
	strcat( info, " I" );
	itoa( m->id, &info[strlen(info)], 16 );
	strcat( info, " C" );
	uint8_t len = strlen(info);
	memcpy( &info[len], m->data, 4 );
	info[ len + 4 ] = '\0';
	lcdPosString( 0, 1, info );
}
